package com.allenkerr.service.impl;

import com.allenkerr.dao.BookRepository;
import com.allenkerr.model.Book;
import com.allenkerr.service.BookService;
import com.allenkerr.vo.BookSearchParams;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.CachedIntrospectionResults;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookRepository bookDao;
    @Autowired
    private ElasticsearchTemplate esTemplate;

    @Override
    public Book save(Book book) {
        return bookDao.save(book);
    }

    @Override
    public void delete(Book book) {
        bookDao.delete(book);
    }

    @Override
    public Book findOne(String id) {
        return bookDao.findOne(id);
    }

    @Override
    public Iterable<Book> findAll() {
        return bookDao.findAll();
    }

    @Override
    public Page<Book> findByAuthor(String author, PageRequest pageRequest) {
        return bookDao.findByAuthor(author, pageRequest);
    }

    @Override
    public List<Book> findByTitle(String title) {
        return bookDao.findByTitle(title);
    }

    @Override
    public Map<String, List<Book>> findByTitleIsLike(String title) {
        Map<String, List<Book>> map = new HashMap<>(4);

        List<Book> isLike = bookDao.findByTitleIsLike(title);
        map.put("findByTitleIsLike", isLike);

//        List<Book> isNear = bookDao.findByTitleIsNear(title);
//        map.put("findByTitleIsNear", isNear);

        List<Book> contains = bookDao.findByTitleContains(title);
        map.put("findByTitleContains", contains);

        List<Book> containing = bookDao.findByTitleContaining(title);
        map.put("findByTitleContaining", containing);

        return map;
    }

    @Override
    public Iterator<Book> init(List<Book> bookList) {
        esTemplate.deleteIndex(Book.class);
        esTemplate.createIndex(Book.class);
        esTemplate.putMapping(Book.class);
        esTemplate.refresh(Book.class);

        Iterable<Book> bookIterable = bookDao.save(bookList);
        return bookIterable.iterator();
    }

    @Override
    public List<Book> listBooks(BookSearchParams searchParams) {
        if (searchParams == null) {
            return Collections.emptyList();
        }
        List<Criteria> criteriaList = new LinkedList<>();
        String id = searchParams.getId();
        if (id != null) {
            Criteria criteria = Criteria.where("id").contains(id);
            criteriaList.add(criteria);
        }
        String title = searchParams.getTitle();
        if (title != null) {
            Criteria criteria = Criteria.where("title").contains(title);
            criteriaList.add(criteria);
        }
        String author = searchParams.getAuthor();
        if (author != null) {
            Criteria criteria = Criteria.where("author").contains(author);
            criteriaList.add(criteria);
        }
        String releaseDate = searchParams.getReleaseDate();
        if (releaseDate != null) {
            Criteria criteria = Criteria.where("releaseDate").is(releaseDate);
            criteriaList.add(criteria);
        }

        if (CollectionUtils.isEmpty(criteriaList)) {
            return Collections.emptyList();
        }
        CriteriaQuery criteriaQuery = new CriteriaQuery(criteriaList.get(0));
        criteriaList.stream()
                .skip(1)
                .forEach(criteriaQuery::addCriteria);
        List<Book> bookList = bookDao.findBooksByQuery(criteriaQuery);
        return bookList;
    }

}